S270: Platform Elements Evolution And Vitto Generation Pipeline Redesign

Documentation for Plans

S270: Platform Elements Evolution and Vitto Generation Pipeline Redesign

Session: 270 | Branch: session-265-273 | Date: 2026-03-25/26 Agent: Claude Code (Opus 4.6) | Status: Partial completion — wiring done, pipeline fix identified but not validated


1. Session Mission

Two objectives:

  1. Platform Elements Evolution (S269 continuation): Wire the 5 remaining integration gaps from the S269 Platform Elements framework so the full editing loop works end-to-end (click element → context in chat → Vitto generates mutations → live DOM update → source sync).

  2. Fix Vitto's generation pipeline: Vitto was always generating Angular/rspack output instead of Platform Elements HTML, even for simple CRUD platforms. Root cause analysis revealed 5 cascading defaults preventing PE auto-detection from ever triggering.

A third objective emerged during the session: redesign Vitto's output mode decision system — the current architecture has a fundamental semantic overload bug where BOTH means both "run both output paths" AND "auto-detect for me."


2. Work Completed

A. Platform Elements Integration Gaps (5/5 wired)

Gap What Was Done Files
1. Debounced blob URL write-back Added peMutationWriteBack Subject in PreviewService. After applyMutationsToSource() updates peSourceHtml, triggers debounced (500ms) blob URL recreation so refresh doesn't lose mutations. preview.service.ts
2. Click-to-Vitto context signal Created PE_ELEMENT_CONTEXT_SIGNAL InjectionToken in vitto-chat, wired through Angular adapter (plugin-presets.ts), injected in AiPanelTabsComponent, provided in gograb-dev app.config.ts with computed() transform from PreviewBridgeService.peElementContext() → PEElementContext. ai-panel-tabs.component.ts, plugin-presets.ts, app.config.ts
3. Entity cache HTTP fetching Added fetchEntitySchemas() in PreviewService using native fetch() + auth token to hit GET /data/schemas/:collection for each entity discovered in PE HTML. Best-effort, silent on failure. preview.service.ts
4. Suggestion engine → quickActions PE_ELEMENT_CONTEXT_SIGNAL factory computes missingFields by diffing entity cache fields against current columns attribute. Chat plugin's quickActions getter shows "Fix N missing field(s)" when non-empty. app.config.ts
5. Backend tool prompt tuning Enhanced platform_elements_edit tool description with full mutation op reference. Strengthened tool output instruction. Added markdown fence stripping in handlePeToolMutations(). platform-elements.plugin.ts, studio-generation-listener.service.ts

B. Generation Pipeline Fixes

Fix What Was Done Files
Body parser 413 Added express.json({ limit: '5mb' }) to backend-vitto-api. Was using NestJS default 100KB. APIs/backend-vitto-api/src/main.ts
Frontend default Changed generateModule() default from 'code' → 'both' studio-vitto-bridge.service.ts
Backend defaults Changed all 4 controller endpoint defaults from ModuleGenOutputMode.CODE → ModuleGenOutputMode.BOTH module-generation.controller.ts
Validation Added 'platform-elements' to @IsIn decorator module-generation.controller.ts
Tool enum Added 'platform-elements' to start_module_generation tool enum + mapping module-gen.plugin.ts
SSE forwarding Added outputMode: d['outputMode'] to tool SSE forwarding module-gen.plugin.ts
Confidence threshold Lowered auto-detection threshold from 0.7 → 0.5 module-gen-phase.executor.ts
Logging Added decision logging for both PE-selected and kept-as-BOTH cases module-gen-phase.executor.ts

C. Explicit UI Controls for Two Paths

Control What Was Done Files
Module panel toggle Added Auto / Platform Elements / Angular button group in chat Module panel chat-module-panel.component.ts/html/scss
Slash commands Added /generate angular <desc> and /generate elements <desc> module-builder.plugin.ts
Callback wiring Wired onModuleGenerate callback in AiPanelTabsComponent to WorkflowStateService ai-panel-tabs.component.ts
Iframe sandbox Fixed PE iframe sandbox (was empty, now allow-scripts allow-same-origin) live-preview.component.html

D. Architecture Analysis

Completed full research of the generation pipeline:


3. Current System State

What Works

What Partially Works

What Exists but Is NOT Fully Functional

What Is Still Missing


4. Critical Gaps

Gap A: BOTH Semantic Overload (Root Cause of Angular-Only Generation)

Why it matters: This is the #1 reason Vitto generates Angular instead of PE. When auto-detection keeps BOTH (LLM recommends 'code' or fails), the execute phase runs BOTH visual AND code paths (lines 143+156 of execute.phase.ts), always producing Angular files.

Root cause: BOTH was designed in early sessions to mean "generate both visual metadata AND Angular code." S269 repurposed it as an auto-detect trigger without changing its execution semantics.

What prevents correct behavior: The execute phase treats BOTH as "run both paths," not "the system chose code." There's no way to distinguish "user wants both outputs" from "auto-detection defaulted to code."

Gap B: No Deterministic Format Resolution

Why it matters: Every generation wastes an LLM round trip (~2-3 seconds, ~200 tokens) to decide PE vs code, even for obvious cases (3-entity CRUD → PE, real-time dashboard → Angular).

Root cause: The ANALYZE phase already produces entity counts, complexity assessments, and building blocks, but the format decision doesn't use them programmatically.

Gap C: Inconsistent Entry Points

Why it matters: 8+ entry points each manage their own outputMode default. Any new feature that triggers generation will get the default wrong unless the developer knows about all the others.

Root cause: No centralized default. Each layer independently chooses a fallback.

Gap D: gograb-space Missing PE Context Wiring

Why it matters: The user runs Studio from gograb-space (port 6200), not gograb-dev (port 6300). The PE_ELEMENT_CONTEXT_SIGNAL provider was only added to gograb-dev's app.config.ts.

Root cause: Session only wired the provider in one app, not all apps that use AiPanelTabsComponent.

Gap E: No End-to-End Validation

Why it matters: Despite all fixes, no one has confirmed the complete chain works: chat message → Vitto agent → start_module_generation(outputMode: 'platform-elements') → PE HTML generated → SSE forwarded with outputMode → frontend routes to blob URL → instant preview.

Root cause: Backend wasn't restarted with all fixes before the session ended.


5. Prioritized Recommendations

STREAM 1: Platform Elements Framework & Implementation

Tier 1 — High Leverage / Low Effort

# Task Why Effort Dependencies
1.1 Wire PE_ELEMENT_CONTEXT_SIGNAL in gograb-space app.config.ts User runs Studio from gograb-space, not gograb-dev. Without this, click-to-Vitto context doesn't work. 15 min None
1.2 End-to-end validation: Restart backend-vitto-api, trigger generation with outputMode: 'platform-elements' explicitly, verify blob URL preview appears Proves the entire chain works 30 min Backend restart
1.3 Wire Vibe Universe generator's outputFormat signal to the same centralized defaults Vibe Universe is a major generation entry point that currently manages its own output mode 30 min None

Tier 2 — Medium Effort / High Impact

# Task Why Effort Dependencies
1.4 Surface format decision in generation activity feed Users need to see "Format: Platform Elements (instant HTML)" or "Format: Angular (full compilation)" in the chat 1-2 hours None
1.5 Add PE context wiring to all apps with AiPanelTabsComponent gograb-admin, gograb-ai, gograb-space all render the chat panel 1 hour 1.1
1.6 Integrate suggestion engine output into chat plugin enrichment generateSuggestions() exists but its full output (not just missingFields) isn't fed into chat context 2 hours 1.1

Tier 3 — Large / Transformative

# Task Why Effort Dependencies
1.7 Platform Elements Angular hybrid build pipeline Build PE elements as Angular Elements for embedding in Angular apps — documented in S269 roadmap 1-2 days S269 spec
1.8 CRUD Builder UI for Platform Elements Visual drag-and-drop entity-to-element binding, column picker, expression builder 2-3 days 1.6

STREAM 2: Vitto Internal Thinking & Decision Processes

Tier 1 — High Leverage / Low Effort

# Task Why Effort Dependencies
2.1 Add AUTO to ModuleGenOutputMode enum and replace all BOTH defaults with AUTO. Add resolution logic in phase executor that converts AUTO → exactly one of CODE or PLATFORM_ELEMENTS before EXECUTE runs. Eliminates the BOTH semantic overload — the #1 root cause of Angular-only generation 1-2 hours None
2.2 Centralize the default outputMode into ModuleGenRequest type or a shared constant, and remove per-endpoint defaults Prevents cascading default bugs. New entry points automatically get the right default. 30 min 2.1
2.3 Add logging to format decision in ALL cases — not just when PE is selected. Log the raw LLM response, parsed JSON, and final decision. Currently only logs when PE is chosen. When code is kept, there's zero visibility into why. 15 min None

Tier 2 — Medium Effort / High Impact

# Task Why Effort Dependencies
2.4 Deterministic format resolver using ANALYZE output Eliminates LLM round trip for 80% of cases. Simple rules: entityCount ≤ 10 + no complex features → PE; entityCount > 10 or complex features → CODE; ambiguous → LLM fallback 2-3 hours 2.1
2.5 Emit module-gen.format-decision SSE event for ALL decisions (not just PE) and surface it in frontend activity feed + chat status Users see "Output: Platform Elements (3 entities, simple CRUD)" and can understand/override 2 hours 2.4
2.6 Deprecate VISUAL output mode Only used by MCP hardcoded path. Generates metadata without code — no user-facing value. Adds branching complexity to execute phase. 1 hour Audit MCP consumers
2.7 Unify SSE forwarding into a generic passthrough Currently the module-gen.plugin.ts manually lists every field to forward. New fields are silently dropped. Replace with ...d spread or a whitelist that's co-located with the emit site. 1-2 hours None

Tier 3 — Large / Transformative

# Task Why Effort Dependencies
2.8 Format decision feedback loop Track which format users override (via Module panel toggle) and feed back into the deterministic resolver as learned preferences per space/universe 1-2 days 2.4, 2.5
2.9 Vitto system prompt enrichment for PE awareness Add PE generation awareness to Vitto's main system prompt so it naturally chooses platform-elements outputMode when calling start_module_generation for simple platforms, without needing the separate auto-detection phase 2-3 hours 2.1
2.10 Pipeline phase telemetry dashboard Track decision confidence, format selection rates, generation times by format, user overrides — surface in Observatory 1-2 days 2.5

6. The One Highest-Leverage Next Step

Task 2.1: Add AUTO to ModuleGenOutputMode and replace all BOTH defaults.

This is a ~1-2 hour change that fixes the fundamental architectural flaw. Without it, every other fix is a band-aid — the BOTH overload will keep causing Angular-only generation. The change is:

  1. Add AUTO = 'auto' to the enum (1 line)
  2. Add resolution in module-gen-phase.executor.ts after ANALYZE:
    if (session.request.outputMode === ModuleGenOutputMode.AUTO) {
      session.request.outputMode = resolveFormat(analyze) ?? await llmDecideFormat(analyze);
    }
    
  3. Change all 8+ defaults from BOTH to AUTO
  4. BOTH retains its original meaning: "generate both visual AND code outputs"

This unblocks everything else. Tasks 2.4, 2.5, 2.8 all depend on clean AUTO semantics.


7. Files / Systems to Inspect

Generation Pipeline (Backend)

File Why
APIs/backend-vitto-api/src/app/module-generation/module-generation.types.ts ModuleGenOutputMode enum — add AUTO here
APIs/backend-vitto-api/src/app/module-generation/phases/module-gen-phase.executor.ts Auto-detection logic (lines 236-273), resolution point
APIs/backend-vitto-api/src/app/module-generation/phases/execute.phase.ts Three-way branching (lines 82, 143, 156) — PE vs VISUAL/BOTH vs CODE/BOTH
APIs/backend-vitto-api/src/app/module-generation/module-generation.controller.ts 4 endpoints with outputMode defaults
APIs/backend-vitto-api/src/app/module-generation/platform-generation.controller.ts Platform endpoint default
APIs/backend-vitto-api/src/app/tools/plugins/module-gen.plugin.ts Agent loop tool — enum, mapping, SSE forwarding
APIs/backend-vitto-api/src/app/mcp-server/mcp-server.service.ts MCP path — hardcoded to VISUAL
APIs/backend-vitto-api/src/prompts/module-gen/system-output-format-decision.prompt.md LLM decision prompt
APIs/backend-vitto-api/src/prompts/module-gen/implement-platform-elements.prompt.md PE generation prompt
APIs/backend-vitto-api/src/main.ts Body parser limit (already fixed to 5MB)

Frontend Generation / Preview

File Why
libs/libs-structural/vitto-studio/src/lib/services/studio-generation-listener.service.ts SSE event routing — handleModuleGenerated branches on outputMode
libs/libs-structural/vitto-studio/src/lib/services/preview.service.ts PE preview (blob URL), mutation write-back, entity cache
libs/libs-structural/vitto-studio/src/lib/services/studio-vitto-bridge.service.ts generateModule() default outputMode
libs/libs-structural/vitto-studio/src/lib/services/workflow-state.service.ts startWorkflow() outputMode passthrough
libs/libs-structural/vitto-studio/src/lib/components/live-preview/live-preview.component.ts Preview mode switching (rspack vs PE vs space)
libs/libs-structural/platform-preview/src/lib/services/preview-bridge.service.ts peElementContext signal

Chat Plugin System

File Why
libs/libs-ai/chat-plugin-core/src/lib/plugins/generation/module-builder.plugin.ts /generate angular, /generate elements slash commands
libs/libs-ai/chat-plugin-core/src/lib/plugins/generation/platform-elements.plugin.ts PE chat plugin with quickActions
libs/libs-ai/chat-plugin-core/src/lib/composition/plugin-preset.factory.ts onModuleGenerate callback signature
libs/libs-ai/vitto-chat/src/lib/plugins/plugin-presets.ts Angular adapter for plugin config
libs/libs-ai/vitto-chat/src/lib/components/ai-panel-tabs/ai-panel-tabs.component.ts PE_ELEMENT_CONTEXT_SIGNAL injection, onModuleGenerate wiring
libs/libs-ai/vitto-chat/src/lib/components/generation/chat-module-panel/chat-module-panel.component.ts Output mode toggle UI

App Configs (PE_ELEMENT_CONTEXT_SIGNAL wiring)

File Why
apps/gograb-dev/src/app/app.config.ts ✅ Already wired
apps/gograb-space/src/app/app.component.ts ❌ NOT wired — user runs Studio here
apps/gograb-ai/src/app/pages/vitto-chat/vitto-chat-page.component.ts May need wiring

Vibe Universe Generator

File Why
libs/libs-structural/vibe-universe/src/lib/components/vibe-universe-generator/vibe-universe-generator.component.ts Own outputFormat signal (lines 1292, 1341, 2984) — needs centralization

8. Validation Checklist

Before Implementing Changes

After Implementing Changes

Edge Cases


9. MCP and Codebase Guidance

Tools to Use

Tool When
preflight({ task: "..." }) Start of session — get context, conventions, warnings
find_similar({ query: "..." }) When encountering familiar problems — search prior decisions
convention({ action: "get", category: "module-generation" }) Before modifying generation pipeline — check conventions
intelligence({ action: "recall", situation: "..." }) When debugging — find similar episodes
intelligence({ action: "simulate", ... }) When choosing between approaches — simulate outcomes
intelligence({ action: "calibrate", rawConfidence: X, domain: "module-generation" }) Before logging decisions — calibrate confidence
log_decision({ ... }) After any non-trivial implementation choice
outcome({ action: "report", ... }) After validating changes work/don't work
intelligence({ action: "reflect", ... }) After completing significant work — capture lessons

Key Conventions (from S270)

  1. ModuleGenOutputMode defaults MUST be centralized — never hardcode 'code' as default in individual entry points
  2. SSE forwarding requires explicit field inclusion — new fields emitted by execute.phase.ts must be manually added to module-gen.plugin.ts forwarding object
  3. Module boundary: vitto-chat cannot import from platform-preview — use InjectionToken pattern for cross-boundary signals

Prior Decision IDs to Reference


10. COPY/PASTE PROMPT FOR SESSION 270 CONTINUATION

SESSION CONTINUATION: S270 — Platform Elements Evolution & Vitto Pipeline Redesign

## Mission
Two parallel streams:
1. PLATFORM ELEMENTS: Complete PE framework integration, validate end-to-end generation
2. VITTO INTERNALS: Fix the output mode decision system so PE generation actually triggers

## Current State
- 5 PE integration gaps WIRED but NOT validated end-to-end
- Generation pipeline defaults FIXED (CODE → BOTH) but fundamental BOTH overload remains
- Module panel has Auto/PE/Angular toggle, /generate slash commands exist
- Body parser raised to 5MB
- PE_ELEMENT_CONTEXT_SIGNAL wired in gograb-dev but NOT gograb-space (where user runs Studio)
- Backend must be restarted to pick up all changes

## Critical Gaps (Priority Order)

### STREAM 2 (Vitto Internals) — Do First
1. **Add AUTO to ModuleGenOutputMode enum** — BOTH means "run both paths" not "decide for me". Add AUTO = 'auto', replace all defaults, add resolution logic in module-gen-phase.executor.ts after ANALYZE. ~1-2 hours.
2. **Deterministic format resolver** — Use ANALYZE output (entity count ≤10, no complex features → PE; else → CODE). LLM only for ambiguous cases. ~2-3 hours.
3. **Surface format decision to user** — Emit in activity feed so user sees "Output: Platform Elements (instant HTML)" vs "Output: Angular (full compilation)". ~2 hours.
4. **Centralize default outputMode** — Single constant, not per-endpoint defaults. ~30 min.
5. **Unify SSE forwarding** — Stop manually listing fields. Use spread or co-located whitelist. ~1-2 hours.

### STREAM 1 (PE Framework) — After Stream 2 Basics
1. **Wire PE_ELEMENT_CONTEXT_SIGNAL in gograb-space app.config** — 15 min
2. **E2E validation** — Restart backend, generate with explicit PE mode, verify blob URL preview
3. **Wire Vibe Universe outputFormat** — Connect to centralized system
4. **Integrate full suggestion engine output** into chat context

## Key Files to Inspect First
- `APIs/backend-vitto-api/src/app/module-generation/module-generation.types.ts` — enum definition
- `APIs/backend-vitto-api/src/app/module-generation/phases/module-gen-phase.executor.ts:236-273` — auto-detection
- `APIs/backend-vitto-api/src/app/module-generation/phases/execute.phase.ts:82-156` — three-way branch
- `APIs/backend-vitto-api/src/app/tools/plugins/module-gen.plugin.ts` — tool enum + SSE forwarding

## Warnings
- BOTH overload is the #1 root cause — don't add more band-aids, fix the enum
- Backend must be restarted after ANY changes to controllers/tools/main.ts
- User runs Studio from gograb-space (port 6200), not gograb-dev (port 6300)
- MCP path (mcp-server.service.ts) hardcodes VISUAL — audit before deprecating
- No git commits were made in S270 (constraint: concurrent session on same branch)

## MCP Tools
Use preflight, find_similar, convention, intelligence, log_decision, outcome.
Key convention: "ModuleGenOutputMode defaults MUST be centralized"
Key decisions: dev_1774534762101_1om7w68 (cascading defaults), dev_1774534783563_v2360k6 (BOTH overload)

## How to Proceed
1. Run preflight({ task: "S270 continuation" })
2. Start with Task 2.1 (AUTO enum) — it unblocks everything else
3. Validate E2E after each change by restarting backend and generating a simple CRUD platform
4. Log decisions and outcomes via MCP
5. Act as a senior engineer: correctness over speed, no hallucination, verify assumptions

Generated by Claude Code (S270) — 2026-03-26